#!/bin/sh
#
# $NetBSD: checksum,v 1.9 2006/07/18 21:39:39 jlam Exp $
#
# Copyright (c) 2006 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Johnny C. Lam.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#        This product includes software developed by the NetBSD
#        Foundation, Inc. and its contributors.
# 4. Neither the name of The NetBSD Foundation nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

######################################################################
#
# NAME
#	checksum -- checksum files
#
# SYNOPSIS
#	checksum [options] distinfo [file ...]
#
# DESCRIPTION
#	checksum will verify the checksums in the distinfo file for each
#	of the files specified.
#
# OPTIONS
#	-a algorithm	Only verify checksums for the specified algorithm.
#	-s suffix	Strip the specified suffix from the file names
#			when searching for the checksum.
#
######################################################################

set -e		# exit on errors

: ${DIGEST:=robotpkg_digest}
: ${CAT:=cat}
: ${ECHO:=echo}
: ${TEST:=test}

self="${0##*/}"

usage() {
	${ECHO} 1>&2 "usage: $self [-a algorithm] [-s suffix] distinfo [file ...]"
}

# Process optional arguments
algorithm=
suffix=
while ${TEST} $# -gt 0; do
	case "$1" in
	-a)	algorithm="$2"; shift 2 ;;
	-s)	suffix="$2"; shift 2 ;;
	--)	shift; break ;;
	-*)	${ECHO} 1>&2 "$self: unknown option -- ${1#-}"
		usage
		exit 1
		;;
	*)	break ;;
	esac
done

# Process required arguments
${TEST} $# -gt 0 || { usage; exit 1; }
distinfo="$1"; shift
files="$@"

if ${TEST} ! -f "$distinfo"; then
	${ECHO} 1>&2 "$self: distinfo file missing: $distinfo"
	exit 1
fi

{ exitcode=0
  algs=" $algorithm "
  while read d_alg d_file d_equals d_checksum; do
	case "$d_alg" in
	"#"*)	continue ;;	# skip comments
	"\$"*)	continue ;;	# skip RCS ID
	"")	continue ;;	# skip empty lines
	Size)	continue ;;	# skip lines holding filesizes, not checksums
	esac

	if ${TEST} -n "$algorithm"; then
		${TEST} "$d_alg" = "$algorithm" || continue
	fi
        case "$d_alg" in
            *" $algs "*);;
            *) algs="$algs $d_alg ";;
        esac

	eval "tmp=\"\$_alg_${d_alg}\""
	${TEST} -n "$tmp" || eval "_alg_${d_alg}=\"$files\""

	for file in $files; do
		sfile="${file%$suffix}"
		${TEST} "$d_file" = "($sfile)" || continue

		eval "tmp=\"\$_alg_${d_alg}\""
		case "$tmp" in
		"$file"|"$file "*)	tmp_pre= ;;
		*" $file")		tmp_pre="${tmp%% $file}" ;;
		*)			tmp_pre="${tmp%% $file *} " ;;
		esac
		case "$tmp" in
		"$file"|*" $file")	tmp_post= ;;
		"$file "*)		tmp_post="${tmp##$file }" ;;
		*)			tmp_post="${tmp##* $file }" ;;
		esac
		tmp="${tmp_pre}${tmp_post}"
		eval "_alg_${d_alg}=\"$tmp\""

		${TEST} -e $file || continue

		if ${TEST} "$d_checksum" = "IGNORE"; then
		    ${ECHO} 1>&2 "$self: Ignoring checksum for $sfile"
		    continue
		fi

		checksum=`${DIGEST} $d_alg < $file`
		if ${TEST} "$d_checksum" != "$checksum"; then
		    ${ECHO} 1>&2 "$self: Checksum $d_alg mismatch for $sfile"
		    exitcode=1
		fi
		break
	done

	eval "tmp=\"\$_alg_${d_alg}\""
	${TEST} -n "$tmp" || eval "_alg_${d_alg}=DONE"
  done
  for algorithm in $algs; do
	eval "tmp=\"\$_alg_${algorithm}\""
	${TEST} -n "$tmp" || tmp="$files"
	if ${TEST} "$tmp" != DONE; then
		for file in $tmp; do
			${ECHO} 1>&2 "$self: No $algorithm checksum recorded for $file"
			exitcode=1
		done
	fi
  done
  exit $exitcode; } < $distinfo
